namespace eval auplay {namespace export *}

proc auplay::_luappend {name args} {
	upvar $name list
	foreach x $args {
		if {$x ni $list} {
			lappend list $x
		}
	}
}

proc auplay::_onchange {name args} {
	upvar $name auplay
	if {[info exists auplay(onchange)]} {
		{*}$auplay(onchange) auplay {*}$args
	}
	foreach v $args {
		if {[info exists auplay(on$v)]} {
			{*}$auplay(on$v) auplay $v
		}
	}
}

proc auplay::_readable {name} {
	upvar $name auplay
	if {[eof $auplay(channel)]} {
		exit 0
	}
	if {[gets $auplay(channel) input] < 0} {
		return;
	}
	foreach line [split $input "\n"] {
		set part [string range $line 1 end]
		set changed {}
		switch -glob -- $line {
		"!unpaused" {
			set auplay(paused) 0
			auplay::_luappend changed paused
		}
		"!paused" {
			set auplay(paused) 1
			auplay::_luappend changed paused
		}
		":*" { # time
			set tmp [split $part /]
			switch [llength $tmp] {
			1 {
				set auplay(time) $part
				auplay::_luappend changed time
				if {$part != $auplay(length)} {
					set auplay(length) $part
					auplay::_luappend changed length
				}
			}
			2 {
				set auplay(time) [lindex $tmp 0]
				auplay::_luappend changed time
				if {[lindex $tmp 1] !=
				    $auplay(length)} {
					set auplay(length) \
					    [lindex $tmp 1]
					auplay::_luappend changed length
				}
			}
			}
		}
		"+*" { # added
			lappend auplay(list) $part
			auplay::_luappend changed list
		}
		"-*" { # remove
			set auplay(list) [lmap x $auplay(list) {
				expr {$x ne $part}
			}]
			auplay::_luappend changed list
		}
		"@*" { # currently playing
			set auplay(current) $part
			set auplay(time) 0
			auplay::_luappend changed current time
		}
		}
		auplay::_onchange auplay {*}$changed
	}
}

proc auplay::create {name args} {
	upvar $name auplay
	set chan [open [list |auplayer {*}$args 2>@stderr] r+]
	fconfigure $chan -buffering line
	fileevent $chan readable [list auplay::_readable $name]
	set auplay(channel) $chan
	set auplay(current) {}
	set auplay(list) {}
	set auplay(paused) 0
	set auplay(time) 0
	set auplay(length) 0
}

proc auplay::destroy {name} {
	upvar $name auplay
	puts $auplay(channel) q
}

proc auplay::previous {name args} {
	upvar $name auplay
	set count [concat {*}$args]
	if {[string is entier $count] && $count > 0} {
		puts $auplay(channel) h[format %u $count]
	} else {
		puts $auplay(channel) h
	}
}

proc auplay::next {name args} {
	upvar $name auplay
	set count [concat {*}$args]
	if {[string is entier $count] && $count > 0} {
		puts $auplay(channel) l[format %u $count]
	} else {
		puts $auplay(channel) l
	}
}

proc auplay::pause {name args} {
	upvar $name auplay
	set setting [concat {*}$args]
	if {[string length $setting] > 0 &&
	    [string is boolean $setting]} {
		if {[string is true $setting]} {
			if {$auplay(paused)} {
				return
			}
		} else {
			if {!$auplay(paused)} {
				return
			}
		}
	}
	puts $auplay(channel) p
}

proc auplay::restart {name} {
	upvar $name auplay
	puts $auplay(channel) r
}

proc auplay::delete {name args} {
	upvar $name auplay
	puts $auplay(channel) d[concat {*}$args]
}

proc auplay::seek {name num} {
	upvar $name auplay
	switch -regexp $num {
	[-+][0-9]+|=[-+]?[0-9]+ {}
	* {return}
	}
	puts $auplay(channel) $num
}

proc auplay::update {name} {
	upvar $name auplay
	puts $auplay(channel) ?
}

proc auplay::hz {name hz} {
	upvar $name auplay
	switch -regexp $hz {
	[0-9]+ {}
	* {return}
	}
	puts $auplay(channel) "$hz z"
}
